#include "stdafx.h"
#include "XTrackerImpl.h"

#if _IS_UI_DESIGNED_ENABLED_

#include "Util.h"
#include "UIUtil.h"

#include "IntSkinImpl.h"
#include "SkinObjMgr.h"
#include "DrawUtil.h"

#define TRACKER_BORDER_SIZE 4

template <class I>
CXTrackerImpl<I>::CXTrackerImpl()
{
    m_HitCode = TrHit_None;
    m_pTrackee = NULL;

    SetCursor(IDC_ARROW);
    ModifyControlFlags(ESkin_CanHover, TRUE);
    ModifyControlFlags(ESkin_NewCursor, TRUE);
    ModifyControlFlags(ESkin_Interactive, TRUE);
}

template <class I>
CXTrackerImpl<I>::~CXTrackerImpl()
{
}

//////////////////////////////////////////////////////////////////////////
// IXTracker

template <class I>
HRESULT CXTrackerImpl<I>::put_Trackee(IN IXFrame* pTrackee)
{
    m_pTrackee = pTrackee;

    if(m_pTrackee != NULL)
    {
        m_pTrackee->put_Margin(0, 0, 0, 0);
        m_pTrackee->SetFrameLayoutType(FLT_VFill | FLT_HFill);
        AutoSizeImpl(FALSE);
    }
    return S_OK;
}

//////////////////////////////////////////////////////////////////////////
// IXFrame

template <class I>
HCURSOR CXTrackerImpl<I>::GetCursor(IN POINT* pt)
{
    do 
    {
        if(m_HitCode == TrHit_None)
            break;

        XSkinObjMgr* pSkinObjMgr = XSkinObjMgr::instance();
        if(pSkinObjMgr == NULL)
            break;

        LPCTSTR szCursor = NULL;
        switch(m_HitCode)
        {
        case TrHit_Left:
        case TrHit_Right:
            szCursor = IDC_SIZEWE;
            break;
        case TrHit_Top:
        case TrHit_Bottom:
            szCursor = IDC_SIZENS;
            break;
        case (TrHit_Left | TrHit_Top):
        case (TrHit_Right | TrHit_Bottom):
            szCursor = IDC_SIZENWSE;
            break;
        case (TrHit_Right | TrHit_Top):
        case (TrHit_Left | TrHit_Bottom):
            szCursor = IDC_SIZENESW;
            break;

        case TrHit_Center:
            szCursor = IDC_HAND;
            break;
        }

        if(szCursor != NULL)
        {
            return pSkinObjMgr->GetCursor(szCursor);
        }
    } while (FALSE);

    return superclass::GetCursor(pt);
}

template <class I>
BOOL CXTrackerImpl<I>::OnMouseDown(POINT* pt)
{
    m_ptOrg = *pt;
    return superclass::OnMouseDown(pt);
}

template <class I>
BOOL CXTrackerImpl<I>::OnMouseUp(POINT* pt)
{
    m_HitCode = TrHit_None;
    return superclass::OnMouseUp(pt);
}

template <class I>
BOOL CXTrackerImpl<I>::OnMouseMove(IN POINT* pt)
{
    IXFrame* pCurCapture = UIUtil::XGetCapture();
    if(pCurCapture == (dynamic_cast<IXFrame*>(this)))
    {
        if(m_HitCode != TrHit_None)
            AdjustTrackee(pt);
    }
    else
    {
        m_HitCode = HitTest(pt);
    }
    return superclass::OnMouseMove(pt);
}

template <class I>
BOOL CXTrackerImpl<I>::OnMouseHover(POINT* pt)
{
    Invalidate();
    return superclass::OnMouseHover(pt);
}

template <class I>
BOOL CXTrackerImpl<I>::OnMouseLeave(POINT* pt)
{
    IXFrame* pCurCapture = UIUtil::XGetCapture();
    if(pCurCapture != (dynamic_cast<IXFrame*>(this)))
    {
        m_HitCode = TrHit_None;
        Invalidate();
    }
    return superclass::OnMouseLeave(pt);
}

template <class I>
void CXTrackerImpl<I>::OnCaptureLost()
{
    m_HitCode = TrHit_None;
    Invalidate();
    superclass::OnCaptureLost();
}

template <class I>
void CXTrackerImpl<I>::PostDraw(XCANVAS xCanvas, const RECT& rcDraw)
{
    superclass::PostDraw(xCanvas, rcDraw);

    RECT rcWnd;
    get_WindowRect(&rcWnd);
    DrawUtil::Rectangle(xCanvas, &rcWnd, RGB(255, 0, 255), (m_HitCode == TrHit_None) ? 2 : 4);
}

//////////////////////////////////////////////////////////////////////////
// IXControl
template <class I>
void CXTrackerImpl<I>::GetAutoSize(OUT LPSIZE pAutoSize)
{
    if(m_pTrackee == NULL)
        superclass::GetAutoSize(pAutoSize);
    else
        m_pTrackee->GetAutoSize(pAutoSize);
}

template <class I>
HRESULT CXTrackerImpl<I>::GetItemByPt(POINT& pt, IXControl** ppItem)
{
    HRESULT hResult = superclass::GetItemByPt(pt, ppItem);
    if(SUCCEEDED(hResult) && (*ppItem) != NULL)
    {
        if(dynamic_cast<IXTracker*>(*ppItem) == NULL)
            (*ppItem) = dynamic_cast<IXControl*>(this);
    }
    return hResult;
}

//////////////////////////////////////////////////////////////////////////
// IXBaseObj
template <class I>
void CXTrackerImpl<I>::OnFinalRelease()
{
    superclass::OnFinalRelease();
    ReleaseData();
}

//////////////////////////////////////////////////////////////////////////
// CXFrameImpl
template <class I>
void CXTrackerImpl<I>::ReleaseData()
{
}

template <class I>
BOOL CXTrackerImpl<I>::OnClicked(const POINT* pt)
{
    return superclass::OnClicked(pt);
}

template <class I>
BOOL CXTrackerImpl<I>::OnRightClicked(const POINT* pt)
{
    return superclass::OnRightClicked(pt);
}

template <class I>
void CXTrackerImpl<I>::OnSizeChanged()
{
    superclass::OnSizeChanged();
}

//////////////////////////////////////////////////////////////////////////
// CXTrackerImpl
template <class I>
DWORD CXTrackerImpl<I>::HitTest(const POINT* pt)
{
    RECT rcWnd;
    get_WindowRect(&rcWnd);

    if(!::PtInRect(&rcWnd, *pt))
        return TrHit_None;

    DWORD dwHitCode = TrHit_None;
    if(pt->x <= rcWnd.left + TRACKER_BORDER_SIZE)
        dwHitCode |= TrHit_Left;
    else if(pt->x >= rcWnd.right - TRACKER_BORDER_SIZE)
        dwHitCode |= TrHit_Right;

    if(pt->y <= rcWnd.top + TRACKER_BORDER_SIZE)
        dwHitCode |= TrHit_Top;
    else if(pt->y >= rcWnd.bottom - TRACKER_BORDER_SIZE)
        dwHitCode |= TrHit_Bottom;

    if(dwHitCode == TrHit_None)
        dwHitCode = TrHit_Center;

    return dwHitCode;
}

template <class I>
void CXTrackerImpl<I>::AdjustTrackee(const POINT* pt)
{
    RECT rcClient;
    get_ClientRect(&rcClient);

    if(IntSkinImpl::CheckFlags(m_HitCode, TrHit_Center))
    {
        ::OffsetRect(&rcClient, (pt->x - m_ptOrg.x), (pt->y - m_ptOrg.y));
    }
    else
    {
        if(IntSkinImpl::CheckFlags(m_HitCode, TrHit_Left))
            rcClient.left -= (m_ptOrg.x - pt->x);

        if(IntSkinImpl::CheckFlags(m_HitCode, TrHit_Top))
            rcClient.top -= (m_ptOrg.y - pt->y);

        if(IntSkinImpl::CheckFlags(m_HitCode, TrHit_Right))
            rcClient.right -= (m_ptOrg.x - pt->x);

        if(IntSkinImpl::CheckFlags(m_HitCode, TrHit_Bottom))
            rcClient.bottom -= (m_ptOrg.y - pt->y);

        put_Size(rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
    }

    put_Pos(rcClient.left, rcClient.top);

    m_ptOrg = *pt;
}

#endif // _ENABLE_UI_DESIGNER_